//std::vector i/o
//$Id: stream_serializer.h 354 2010-03-09 17:29:03Z Oleg.Bulychov $
#pragma once

#include <iostream>
#include "src/heo/include/reflection.h"
#include "src/heo/include/ptr_visit.h"

namespace meta
{
//__________________________________________________________________________________
class ifstream_visitor:
    public meta::visitor< ifstream_visitor >
{
public:
    std::ifstream& in_;

    explicit ifstream_visitor(std::ifstream& in): in_(in)
    {}

    template<typename T, typename D>
    void visit_Array(T* pt, size_t N, char const* szName, D const& d)
    {
        for (size_t i = 0; i < N; ++i, ++pt)
            visit_T(*pt);
    }

    template<typename T, typename D>
    void visit_Ptr(T* pt, char const* szName, D const& d)
    {
        d.accept(pt, *this);
    }

    template<typename T, typename D>
    void visit_Class(T& t, char const* szName, D const&)
    {
        t.accept(*this);
    }

    template<typename T, typename D>
    void visit(T& t, char const* szName, D const& d)
    {
        in_.read((char*)&t, sizeof(T));
    }

    template<typename D>
    void visit(std::string& s, char const* szName, D const& d)
    {
        size_t len = 0;
        visit_T(len);
        s.resize(len);
        if (len)
            in_.read(&s[0], len);
    }

    template<typename X, typename D>
    void visit(std::vector<X>& v, char const* szName, D const& d)
    {
        //:NOTE: vector<bool> may be totally broken and can't be treated as a C array
        //:use vector<char> instead
        size_t vsize = 0;
        visit_T(vsize);
        v.resize(vsize);
        for (size_t i = 0; i < vsize; ++i)
        {
            visit_T(v[i]);
        }
    }

    template<typename T>
    void operator >>(T& t)
    {
        visit_T(t, "");
    }
};
//__________________________________________________________________________________
class ofstream_visitor:
    public meta::visitor< ofstream_visitor >
{
public:
    std::ofstream& out_;

    explicit ofstream_visitor(std::ofstream& out): out_(out)
    {}

    template<typename T, typename D>
    void visit_Array(T* pt, size_t N, char const* szName, D const& d)
    {
        for (size_t i = 0; i < N; ++i, ++pt)
            visit_T(*pt);
    }

    template<typename T, typename D>
    void visit_Ptr(T* pt, char const* szName, D const& d)
    {
        d.accept(pt, *this);
    }

    template<typename T, typename D>
    void visit_Class(T& t, char const* szName, D const&)
    {
        t.accept(*this);
    }

    template<typename T, typename D>
    void visit(T& t, char const* szName, D const& d)
    {
        out_.write((char const*)&t, sizeof(T));
    }

    template<typename D>
    void visit(std::string& s, char const* szName, D const& d)
    {
        size_t len = s.length();
        visit_T(len);
        out_.write(s.c_str(), len);
    }

    template<typename X, typename D>
    void visit(std::vector<X>& v, char const* szName, D const& d)
    {
        //:NOTE: vector<bool> may be totally broken and can't be treated as a C array
        //:use vector<char> instead
        size_t vsize = v.size();
        visit_T(vsize);
        for (size_t i = 0; i < vsize; ++i)
        {
            visit_T(v[i]);
        }
    }

    template<typename T>
    void operator <<(T& t)
    {
        visit_T(t, "");
    }
};
}//meta
//__________________________________________________________________________________
REGISTER_VISITOR(meta::ofstream_visitor);
REGISTER_VISITOR(meta::ifstream_visitor);
//__________________________________________________________________________________

//EOF!
